/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.nodes;
import java.beans.Beans;
import java.beans.PropertyEditor;
import java.lang.reflect.*;
import org.openide.util.NbBundle;
/** Support class for <code>Node.Property</code>.
*
* @see Node.Property
* @author Jan Jancura, Jaroslav Tulach, Ian Formanek
* @version 0.21, Mar 24, 1998
*/
public abstract class PropertySupport extends Node.Property {
/** flag whether the property is readable */
private boolean canR;
/** flag whether the property is writable */
private boolean canW;
/** Constructs a new support.
* @param name the name of the property
* @param type the class type of the property
* @param displayName the display name of the property
* @param canR whether the property is readable
* @param canW whether the property is writable
*/
public PropertySupport(String name, Class type, String displayName, String shortDescription, boolean canR, boolean canW) {
super(type);
this.setName(name);
setDisplayName(displayName);
setShortDescription(shortDescription);
this.canR = canR;
this.canW = canW;
}
/* Can read the value of the property.
* Returns the value passed into constructor.
* @return <CODE>true</CODE> if the read of the value is supported
*/
public boolean canRead () {
return canR;
}
/* Can write the value of the property.
* Returns the value passed into constructor.
* @return <CODE>true</CODE> if the read of the value is supported
*/
public boolean canWrite () {
return canW;
}
/** Support for properties from Java Reflection. */
public static class Reflection extends Node.Property {
/** Instance of a bean. */
protected Object instance;
/** setter method */
private Method setter;
/** getter method */
private Method getter;
/** class of property editor */
private Class propertyEditorClass;
/** Create a support with method objects specified.
* The methods must be public.
* @param instance (Bean) object to work on
* @param valueType type of the property
* @param getter getter method, can be <code>null</code>
* @param setter setter method, can be <code>null</code>
* @throws IllegalArgumentException if the methods are not public
*/
public Reflection (Object instance, Class valueType, Method getter, Method setter) {
super (valueType);
if (getter != null && ! Modifier.isPublic (getter.getModifiers ()))
throw new IllegalArgumentException ("Cannot use a non-public getter " + getter); // NOI18N
if (setter != null && ! Modifier.isPublic (setter.getModifiers ()))
throw new IllegalArgumentException ("Cannot use a non-public setter " + setter); // NOI18N
this.instance = instance;
this.setter = setter;
this.getter = getter;
}
/** Create a support with methods specified by name.
* The instance class will be examined for the named methods.
* But if the instance class is not public, the nearest public superclass
* will be used instead, so that the getters and setters remain accessible.
* @param instance (Bean) object to work on
* @param valueType type of the property
* @param getter name of getter method, can be <code>null</code>
* @param setter name of setter method, can be <code>null</code>
* @exception NoSuchMethodException if the getter or setter methods cannot be found
*/
public Reflection (Object instance, Class valueType, String getter, String setter)
throws NoSuchMethodException {
this (
instance, valueType,
// find the getter ()
getter == null ? null : findAccessibleClass (instance.getClass ()).getMethod (
getter, new Class[0]
),
// find the setter (valueType)
setter == null ? null : findAccessibleClass (instance.getClass ()).getMethod (
setter, new Class[] { valueType }
)
);
}
/** Find the nearest superclass (or same class) that is public to this one. */
private static Class findAccessibleClass (Class clazz) {
if (Modifier.isPublic (clazz.getModifiers ())) {
return clazz;
} else {
Class sup = clazz.getSuperclass ();
if (sup == null) return Object.class; // handle interfaces
return findAccessibleClass (sup);
}
}
// [PENDING] should use Beans API in case there is overriding BeanInfo --jglick
/** Create a support based on the property name.
* The getter and setter methods are constructed by capitalizing the first
* letter in the name of propety and prefixing it with <code>get</code> and
* <code>set</code>, respectively.
*
* @param instance object to work on
* @param valueType type of the property
* @param property name of property
* @exception NoSuchMethodException if the getter or setter methods cannot be found
*/
public Reflection (Object instance, Class valueType, String property)
throws NoSuchMethodException {
this (
instance, valueType,
firstLetterToUpperCase (property, "get"), // NOI18N
firstLetterToUpperCase (property, "set") // NOI18N
);
}
/** Helper method to convert the first letter of a string to uppercase.
* And prefix the string with some next string.
*/
private static String firstLetterToUpperCase (String s, String pref) {
switch (s.length ()) {
case 0:
return pref;
case 1:
return pref + Character.toUpperCase (s.charAt (0));
default:
return pref + Character.toUpperCase (s.charAt (0)) + s.substring (1);
}
}
/* Can read the value of the property.
* @return <CODE>true</CODE> if the read of the value is supported
*/
public boolean canRead () {
return getter != null;
}
/* Getter for the value.
* @return the value of the property
* @exception IllegalAccessException cannot access the called method
* @exception IllegalArgumentException wrong argument
* @exception InvocationTargetException an exception during invocation
*/
public Object getValue () throws
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (getter == null) throw new IllegalAccessException ();
Object valideInstance = Beans.getInstanceOf (instance, getter.getDeclaringClass());
return getter.invoke (valideInstance, new Object [0]);
}
/* Can write the value of the property.
* @return <CODE>true</CODE> if the read of the value is supported
*/
public boolean canWrite () {
return setter != null;
}
/* Setter for the value.
* @param val the value of the property
* @exception IllegalAccessException cannot access the called method
* @exception IllegalArgumentException wrong argument
* @exception InvocationTargetException an exception during invocation
*/
public void setValue (Object val) throws
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (setter == null) throw new IllegalAccessException ();
Object valideInstance = Beans.getInstanceOf (instance, setter.getDeclaringClass());
setter.invoke (valideInstance, new Object [] {val});
}
/* Returns property editor for this property.
* @return the property editor or <CODE>null</CODE> if there should not be
* any editor.
*/
public PropertyEditor getPropertyEditor () {
if (propertyEditorClass != null)
try {
return (PropertyEditor) propertyEditorClass.newInstance ();
} catch (InstantiationException ex) {
} catch (IllegalAccessException iex) {
}
return super.getPropertyEditor ();
}
/** Set the property editor explicitly.
* @param clazz class type of the property editor
*/
public void setPropertyEditorClass (Class clazz) {
propertyEditorClass = clazz;
}
}
/** A simple read/write property.
* Subclasses should implement
* {@link #getValue} and {@link #setValue}.
*/
public static abstract class ReadWrite extends PropertySupport {
/** Construct a new support.
* @param name the name of the property
* @param type the class type of the property
* @param displayName the display name of the property
* @param shortDescription a short description of the property
*/
public ReadWrite(String name, Class type, String displayName,
String shortDescription) {
super(name, type, displayName, shortDescription, true, true);
}
}
/** A simple read-only property.
* Subclasses should implement {@link #getValue}.
*/
public static abstract class ReadOnly extends PropertySupport {
/** Construct a new support.
* @param name the name of the property
* @param type the class type of the property
* @param displayName the display name of the property
* @param shortDescription a short description of the property
*/
public ReadOnly(String name, Class type, String displayName,
String shortDescription) {
super(name, type, displayName, shortDescription, true, false);
}
/* Setter for the value.
* @param val the value of the property
* @exception IllegalAccessException cannot access the called method
* @exception IllegalArgumentException wrong argument
* @exception InvocationTargetException an exception during invocation
*/
public void setValue (Object val) throws
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
throw new IllegalAccessException("Cannot write to ReadOnly property"); // NOI18N
}
}
/** A simple write-only property.
* Subclasses should implement {@link #setValue}.
*/
public static abstract class WriteOnly extends PropertySupport {
/** Construct a new support.
* @param name the name of the property
* @param type the class type of the property
* @param displayName the display name of the property
* @param shortDescription a short description of the property
*/
public WriteOnly(String name, Class type, String displayName,
String shortDescription) {
super(name, type, displayName, shortDescription, false, true);
}
/* Getter for the value.
* @return the value of the property
* @exception IllegalAccessException cannot access the called method
* @exception IllegalArgumentException wrong argument
* @exception InvocationTargetException an exception during invocation
*/
public Object getValue () throws
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
throw new IllegalAccessException("Cannod read from WriteOnly property"); // NOI18N
}
}
/** Support for the name property of a node. Delegates {@link #setValue} and {@link #getValue}
* to {@link Node#setName} and {@link Node#getName}.
* <p>(Final only for performance, can be unfinaled if desired).
*/
public static final class Name extends PropertySupport {
/** The node to which we delegate the work. */
private final Node node;
/** Create the name property for a node with the standard name and hint.
* @param node the node
*/
public Name (final Node node) {
this(node,
NbBundle.getBundle(PropertySupport.class).getString("CTL_StandardName"),
NbBundle.getBundle(PropertySupport.class).getString("CTL_StandardHint"));
}
/** Create the name property for a node.
* @param node the node
* @param propName name of the "name" property
* @param hint hint message for the "name" property
*/
public Name (final Node node, final String propName, final String hint) {
super(Node.PROP_NAME, String.class, propName, hint,
true, node.canRename());
this.node = node;
}
/* Getter for the value. Delegates to Node.getName().
* @return the name
*/
public Object getValue ()
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
return node.getName();
}
/* Setter for the value. Delegates to Node.setName().
* @param val new name
*/
public void setValue (Object val)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
if (!(val instanceof String)) throw new IllegalAccessException ();
node.setName((String)val);
}
} // end of Name inner class
}
/*
* Log
* 9 Gandalf 1.8 1/12/00 Jesse Glick NOI18N
* 8 Gandalf 1.7 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 7 Gandalf 1.6 7/12/99 Jesse Glick PropertySupport.Reflection
* now correctly handles the case where a non-public instance class is
* specified, but the desired getters/setters are publically declared in a
* public superclass. E.g. DefaultDataObject.getHelpCtx. Similarly done
* for BeanNode a while back.
* 6 Gandalf 1.5 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 5 Gandalf 1.4 4/7/99 Jesse Glick [JavaDoc]
* 4 Gandalf 1.3 3/17/99 Jesse Glick [JavaDoc]
* 3 Gandalf 1.2 3/17/99 Jesse Glick [JavaDoc]
* 2 Gandalf 1.1 2/3/99 David Simonek
* 1 Gandalf 1.0 1/5/99 Ian Formanek
* $
* Beta Change History:
* 0 Tuborg 0.12 --/--/98 Jaroslav Tulach More public setters
* 0 Tuborg 0.13 --/--/98 Jan Jancura equals method removed
* 0 Tuborg 0.20 --/--/98 Jan Formanek complex changes
* 0 Tuborg 0.21 --/--/98 Jan Formanek {Hanz} expert flag removed
*/